#include "mssql_common.h"

void DATABASE_LINK_CONSTRUCT(struct __database_link* dblink, char* SQL_SERVER_IP, int SQL_SERVER_PORT,
                            char* user, char* pass,
                            char* db )
{
    //char s_port[25];
    //itoa(SQL_SERVER_PORT, s_port, 10);     //here 10 means decimal
    strcpy(dblink->SQL_SERVER_IP, SQL_SERVER_IP);
   sprintf(dblink->SQL_SERVER_PORT, "%d", SQL_SERVER_PORT);
   sprintf(dblink->SQL_SERVER, "%s:%d", SQL_SERVER_IP, SQL_SERVER_PORT);
    strcpy(dblink->user, user);
    strcpy(dblink->pass, pass);
    strcpy(dblink->db, db);
}

int MSSQL_CONN_OPEN(MSSQL_CONN* conn, struct __database_link* dblink)
{
    conn->dblink = dblink;
    //建立到MSSQL数据库的连接------------------------   
    dbinit();                         //使用dbinit()函数, 进行freetds操作之前的初始化操作  
    LOGINREC *loginrec = dblogin();   //建立一个到数据库的连接的句柄  
    DBSETLUSER(loginrec, conn->dblink->user);  //向句柄中添加连接数据库的用户  
    DBSETLPWD(loginrec,  conn->dblink->pass);                     //向数据库连接句柄中添加密码  
    conn->dbprocess = dbopen(loginrec, conn->dblink->SQL_SERVER);   //连接数据库,并返回数据库连接结果的句柄  
          
    if(conn->dbprocess == FAIL)                                   //如果连接失败  
    {   
        fprintf(stderr, "Connect Fail\n");                  //在标准错误中输出信息  
        //exit(EXIT_FAILURE);                                 //进程异常退出  
        return 1;
    }  
    else                                                    //如果连接成功  
    {  
        //printf("Connect success\n");  
    }  
           
    if(dbuse(conn->dbprocess, conn->dblink->db) == FAIL)                 //使用某个数据库，如果使用失败  
    {  
        dbclose(conn->dbprocess);                                 //关闭数据库连接句柄, 并且回收相关资源  
        //exit(EXIT_FAILURE);                                 //进程异常退出  
        return 2;
    }  
    return 0;
}

void MSSQL_CONN_RSTSET_CLEAN(RSTSET* rstset)
{
    int i,j;
    for(i = 0; i < rstset->nROW; i++)
        for(j = 0; j < rstset->nCOL; j++)
        {
            if(rstset->SET[i*rstset->nCOL+j] != NULL)
                free(rstset->SET[i*rstset->nCOL+j]);
            /*
            if(rstset->TYPE[i*rstset->nCOL+j] != NULL)
                free(rstset->TYPE[i*rstset->nCOL+j]);
            
            if(rstset->SIZE[i*rstset->nCOL+j] != NULL)
                free(rstset->SIZE[i*rstset->nCOL+j]);
            */
        }
    if(rstset->TYPE != NULL)
        free(rstset->TYPE);
    if(rstset->SIZE != NULL)
        free(rstset->SIZE);
    if(rstset->SET != NULL)
        free(rstset->SET);
}

void mssql_rstset_print(RSTSET* rstset)
{
    int i,j;
    for(i = 0; i < rstset->nROW; i++){
        for(j = 0; j < rstset->nCOL; j++)
        {
            if(rstset->SET[i*rstset->nCOL+j] != NULL)
                fprintf(stdout, "%*s", 20, rstset->SET[i*rstset->nCOL+j]);
        }
        printf("\n");
    }
}

int mssql_select(MSSQL_CONN* conn)
{
    RETCODE erc;
    while((erc = dbresults(conn->dbprocess)) != NO_MORE_RESULTS) {
        int ncols; int row_code; 
        struct col {        //保存列的所有信息
            char *name;     //列名字
            char *buffer;   //存放列数据指针
            int type, size, status;
        } *columns, *pcol;
        
        if(erc == FAIL) {
            fprintf(stderr, "TDS/> dbresults failed.\n");
            return -1;  //exit(1);
        } 
        ncols = dbnumcols(conn->dbprocess);//返回执行结果的列数目 
        if((columns = calloc(ncols, sizeof(struct col))) == NULL) {
            perror(NULL);
            fprintf(stderr, "SYS/> Column Sets space allocated failed.\n");
            return -2;  //exit(1);
        }

        conn->result.SET = (char**)malloc(sizeof(char*) * ncols);
        int RSTiROW = 0;
        
        conn->result.nCOL = ncols;
        /* read metadata and bind. */
        for(pcol = columns; pcol - columns < ncols; pcol++) {
            int c = pcol - columns + 1;
            pcol->name = dbcolname(conn->dbprocess, c); //返回指定列的列名
            pcol->type = dbcoltype(conn->dbprocess, c); //printf("column type: %d\n", pcol->type);
            pcol->size = dbcollen(conn->dbprocess, c); 
            //printf("%*s(%d)", 20, pcol->name, pcol->size);  //显示列名称及字段长度
            if((pcol->buffer = calloc(1, pcol->size)) == NULL) {    //创建列字段数据缓冲区
                perror(NULL);
                fprintf(stderr, "SYS/> Shared Column field buffer allocated failed.\n");
                return -3;  //exit(1);
            }
            /* Parameters
             * dbproc  contains all information needed by db-lib to manage communications with the server.
             * column  Nth column, starting at 1.
             * vartype datatype of the host variable that will receive the data
             * varlen  size of host variable pointed to varaddr
             * varaddr address of host variable
             */
            if((erc = dbbind(conn->dbprocess, c, NTBSTRINGBIND, pcol->size, (BYTE*)pcol->buffer)) == FAIL) {
                fprintf(stderr, "TDS/> Shared Column field buffer dbbind(%d) failed\n", c);
                return -4;  //exit(1);
            }  

            /*  Return values
             *  0 column bound successfully
             * -1 column is NULL.
             * >0 true length of data, had column not been truncated due to insufficient space in the columns bound host variable .
             */
            if(( erc = dbnullbind(conn->dbprocess, c, &pcol->status)) == FAIL) {
                fprintf(stderr, "TDS/> Shared Column field status-word dbnullbind(%d) failed\n", c);
                return -5;  //exit(1);
            }
            //列名称保存到结果集
            conn->result.SET[RSTiROW*ncols + c -1] = (char*)malloc(sizeof(char)*pcol->size);
            sprintf(conn->result.SET[RSTiROW*ncols + c -1], "%s(%d)", pcol->name, pcol->size);
            //printf("%s\n", conn->result.SET[RSTiROW*ncols + c -1]);
        }
        //第一行(列名称)结束，行索引加1
        RSTiROW = RSTiROW + 1; 
        /* 获取每一行所有数据字段指针占用的空间
         * 注意：使用正确的数据类型做单位长度
         */
        int RST_ROW_SIZE = ncols * sizeof(char*);

        //printf("\n");
        /* 打印/读取 每行数据 */
        int c; char **NEW_RSTSET; int NEW_RSTSET_ROW;
        while((row_code = dbnextrow(conn->dbprocess)) != NO_MORE_ROWS) {//读取行数据
            switch(row_code) {
                case REG_ROW:
                    //printf("Current RSTiROW: %d\tRSTSET size: %d\n", RSTiROW, (RST_ROW_SIZE)*(RSTiROW) );
                    //空间扩展后的所有数据行数量
                    NEW_RSTSET_ROW = RSTiROW+1;
                    //扩展新数据行存储空间
                    NEW_RSTSET = (char**)realloc(conn->result.SET, (RST_ROW_SIZE)*NEW_RSTSET_ROW );
                    if(NEW_RSTSET != NULL){
                        conn->result.SET = NEW_RSTSET;
                    }else{
                        fprintf(stderr, "SYS/> Result Set memory space reallocated failed.\n");
                        return -7;
                    }
                    //逐列写入到结果集缓冲区
                    for(pcol=columns, c = 0; pcol - columns < ncols; pcol++, c++) {
                        char *buffer = pcol->status == -1 ? "null" : pcol->buffer;
                        //printf("%*s ", 20, buffer);
                        conn->result.SET[RSTiROW*ncols + c] = (char*)malloc(sizeof(char)*pcol->size);
                        sprintf(conn->result.SET[RSTiROW*ncols + c], "%s", buffer);
                    }
                    //行统计索引加1
                    RSTiROW = RSTiROW + 1;
                    printf("\n"); 
                    break;
                case BUF_FULL: 
                    break;
                case FAIL:
                    fprintf(stderr, "dbresults failed\n");
                    return -6;  //exit(1); 
                    break;
                default:
                    printf("data for computeid %d ignored\n", row_code);
            }
        }

        conn->result.nROW = RSTiROW;
        /* free metadata and data buffers */
        for(pcol=columns; pcol - columns < ncols; pcol++) {
            free(pcol->buffer);
        }
        free(columns);

        if(DBCOUNT(conn->dbprocess) > -1) {/* 得到SQL语句影响的行数 */
            //fprintf(stderr, "%d rows affected\n", DBCOUNT(conn.dbprocess));
            return DBCOUNT(conn->dbprocess);
        }
    }
}


int mssql_query_column_name(MSSQL_CONN *conn, char* table)
{
    RETCODE erc;
    char mssqlbuf[1024]; memset(mssqlbuf, 0x00, sizeof(mssqlbuf));
    sprintf(mssqlbuf, "SELECT * from %s;", table);   
    dbcmd(conn->dbprocess, mssqlbuf); //sql text 保存到数据库连接句柄的缓存中 
    if(dbsqlexec(conn->dbprocess) == FAIL){    
        return -1;                      
    }else{

        while((erc = dbresults(conn->dbprocess)) != NO_MORE_RESULTS) {
            int ncols; int row_code; 
            struct col {        //保存列的所有信息
                char *name;     //列名字
                char *buffer;   //存放列数据指针
                int type, size, status;
            } *columns, *pcol;
            if(erc == FAIL) {
                return 0;  // row > 1, function exit normally.
            } 
            ncols = dbnumcols(conn->dbprocess);//返回执行结果的列数目 
            if((columns = calloc(ncols, sizeof(struct col))) == NULL) {
                perror(NULL);
                fprintf(stderr, "SYS/> Column Sets space allocated failed.\n");
                return -2;  //exit(1);
            }
            conn->result.SET = (char**)malloc(sizeof(char*) * ncols);
            conn->result.TYPE = (int*)malloc(sizeof(int) * ncols);
            conn->result.SIZE = (int*)malloc(sizeof(int) * ncols);

            int RSTiROW = 0;
            conn->result.nCOL = ncols; conn->result.nROW = 1; // column名称 仅此一行
            /* read metadata and bind. */
            for(pcol = columns; pcol - columns < ncols; pcol++) {
                int c = pcol - columns + 1;
                pcol->name = dbcolname(conn->dbprocess, c); //返回指定列的列名
                pcol->type = dbcoltype(conn->dbprocess, c); //printf("column type: %d\n", pcol->type);
                pcol->size = dbcollen(conn->dbprocess, c); 
                //printf("%*s(%d)", 20, pcol->name, pcol->size);  //显示列名称及字段长度
                if((pcol->buffer = calloc(1, pcol->size)) == NULL) {    //创建列字段数据缓冲区
                    perror(NULL);
                    fprintf(stderr, "SYS/> Shared Column field buffer allocated failed.\n");
                    return -3;  //exit(1);
                }
                /* Parameters
                 * dbproc  contains all information needed by db-lib to manage communications with the server.
                 * column  Nth column, starting at 1.
                 * vartype datatype of the host variable that will receive the data
                 * varlen  size of host variable pointed to varaddr
                 * varaddr address of host variable
                 */
                if((erc = dbbind(conn->dbprocess, c, NTBSTRINGBIND, pcol->size, (BYTE*)pcol->buffer)) == FAIL) {
                    fprintf(stderr, "TDS/> Shared Column field buffer dbbind(%d) failed\n", c);
                    return -4;  //exit(1);
                }  

                /*  Return values
                 *  0 column bound successfully
                 * -1 column is NULL.
                 * >0 true length of data, had column not been truncated due to insufficient space in the columns bound host variable .
                 */
                if(( erc = dbnullbind(conn->dbprocess, c, &pcol->status)) == FAIL) {
                    fprintf(stderr, "TDS/> Shared Column field status-word dbnullbind(%d) failed\n", c);
                    return -5;  //exit(1);
                }
                //列名称保存到结果集
                conn->result.SET[RSTiROW*ncols + c -1] = (char*)malloc(sizeof(char)*pcol->size);
                //sprintf(conn->result.SET[RSTiROW*ncols + c -1], "%s(%d)", pcol->name, pcol->size);
                sprintf(conn->result.SET[RSTiROW*ncols + c -1], "%s", pcol->name);

                conn->result.TYPE[RSTiROW*ncols + c -1] = pcol->type;
                conn->result.SIZE[RSTiROW*ncols + c -1] = pcol->size;


                //printf("%s\t", conn->result.SET[RSTiROW*ncols + c -1]); 
            }printf("\n");
            /* free metadata and data buffers */
            for(pcol=columns; pcol - columns < ncols; pcol++) {
                free(pcol->buffer);
            }

            free(columns);
        }
    }
}
#if 0
void sqltext_insert_construct(char* sqltext, char* tablename, struct __result_set* columninfo, ... )
{
    int i;  char temp[1024];
    sprintf(sqltext, "INSERT INTO %s (", tabname);
    for(i = 0; i < columninfo->nCOL; i++){
        strcat(sqltext, columninfo->SET[i]);
        if(i != columninfo->nCOL-1)
            strcat(sqltext, ", ")
    }strcat(sqltext, ") VALUES (");
    for(i = 0; i < columninfo->nCOL; i++){
        if( (columninfo->SIZE[i] == MSSQL2014_AVAIL_COL_SIZE_bit && columninfo->TYPE[i] == MSSQL2014_AVAIL_COL_TYPE_bit) || 
            (columninfo->SIZE[i] == MSSQL2014_AVAIL_COL_SIZE_smallint && columninfo->TYPE[i] == MSSQL2014_AVAIL_COL_TYPE_smallint) ||
            (columninfo->SIZE[i] == MSSQL2014_AVAIL_COL_SIZE_tinyint && columninfo->TYPE[i] == MSSQL2014_AVAIL_COL_TYPE_tinyint) ){
            sprintf(temp, MSSQL2014_AVAIL_COL_C_TYPE_tinyint, )
            strcat(sqltext, temp);
        }
        else if( (columninfo->SIZE[i] == MSSQL2014_AVAIL_COL_SIZE_int && columninfo->TYPE[i] == MSSQL2014_AVAIL_COL_TYPE_int) ){
            sprintf(temp, MSSQL2014_AVAIL_COL_C_TYPE_int, )
            strcat(sqltext, temp);
        }
    }
}
#endif